#include "all.h"
struct thread_block
{
    int fd_A;//源文件句柄
    int fd_B;//目的文件句柄
    size_t start;//文件的写入起始位置
    size_t end;//文件写入的终止位置
};
//获取文件大小
size_t get_filesize(int fd)
{
    struct stat st;
    fstat(fd,&st);
    return st.st_size;
}
//判断是否是目录
int is_dir(char* path)
{
    struct stat st;
    stat(path,&st);
    if(S_ISDIR(st.st_mode))
        return 1;
    else return 0;
}
//字符串处理函数
int endwith(char* s,char c)
{
    if(s[strlen(s)-1]==c)
        return 1;
    else return 0;
    }
//字符串连接
char* str_contact(char* str1,char* str2)
{
    char* result;
    result=(char*)malloc(strlen(str1)+strlen(str2)+1);
    if(!result){
        printf("字符串连接时，内存动态分配失败\n");
        exit(1);
    }
    strcat(result,str1);
    strcat(result,str2);
    return result;
    }
void *thread_copy_fn(void *arg);
void Copy(char *path_A,char *path_B)//复制
{
    struct stat s;
    int fd_A = open(path_A,O_RDONLY);
    int fd_B = open(path_B,O_CREAT|O_WRONLY,0777);
    if(fd_A==-1||fd_B==-1)
    {
        printf("error\n");
        }
    size_t file_size=get_filesize(fd_A);
    size_t thread_size=THREADS_COUNT;
    struct thread_block *blocks=(struct thread_block *)malloc(sizeof(struct thread_block )*thread_size);
    size_t percent=file_size/thread_size;
    int i=0;
    for(;i<thread_size;i++)
    {
        blocks[i].fd_A=fd_A;
        blocks[i].fd_B=fd_B;
        blocks[i].start=i*percent;
        blocks[i].end=blocks[i].start+percent;
        }
    blocks[i].end=file_size;
    pthread_t ptid[thread_size];
    for(i=0;i<thread_size;i++)
    {
        pthread_create(&ptid[i],NULL,thread_copy_fn,&(blocks[i]));
        }
    for(i=0;i<thread_size;i++)
    {
        pthread_join(ptid[i],NULL);
        }
    free(blocks);
    fstat(fd_A,&s);
    chown(path_B,s.st_uid,s.st_gid);
    chmod(path_B,s.st_mode);
    close(fd_A);
    close(fd_B);
    }
//复制函数的多进程实现
void *thread_copy_fn(void *arg)
{
    struct thread_block *block=(struct thread_block *)arg;
    char buf[THREADS_BUFF_SIZE];
    size_t count=block->start;
    int ret;
    ret=lseek(block->fd_A,block->start,SEEK_SET);
    ret=lseek(block->fd_B,block->start,SEEK_SET);
    int bytes_read;
    int bytes_write;
    while(count<block->end)
    {
        bytes_read=read(block->fd_A,buf,sizeof(buf));
        if(bytes_read>0)
        {
            count+=bytes_read;
            if((bytes_read==-1)&&(errno!=EINTR))
                break;
        char *ptr_write=buf;
        while((bytes_write=write(block->fd_B,ptr_write,bytes_read))!=0)
        {
            if((bytes_write==-1)&&(errno!=EINTR))
                break;
            if(bytes_write==bytes_read)
                break;
            else if(bytes_write>0)
            {
                ptr_write+=bytes_write;
                bytes_read-=bytes_write;
                }
            }
            if(bytes_write==-1)
                break;
            }
        }
        pthread_exit(NULL);
    }
//文件夹的复制
void copy_folder(char* source_path,char *destination_path)
{
    if(!opendir(destination_path))
    {
        if(mkdir(destination_path,0777))
        {
            printf("创建文件夹失败！\n");
            }
        }
    char* path=(char*)malloc(512);
    path=str_contact(path,source_path);//字符串连接
    struct dirent* filename;
    DIR* dp=opendir(path);
    while((filename=readdir(dp))!=NULL)
    {
        if(path!=NULL)
        {
            memset(path,0,sizeof(path));
            }
        path=str_contact(path,source_path);
        char *file_source_path;
        file_source_path=(char*)malloc(512);
        if(!endwith(source_path,'/'))
        {
            file_source_path=str_contact(file_source_path,source_path);
            file_source_path=str_contact(source_path,"/");
            }else{
                    file_source_path=str_contact(file_source_path,source_path);
                }
            char *file_destination_path;
            file_destination_path=(char*)malloc(512);
            if(!endwith(destination_path,'/'))
            {
                file_destination_path=str_contact(file_destination_path,destination_path);
                file_destination_path=str_contact(destination_path,"/");
                }else{
                        file_destination_path=str_contact(file_destination_path,destination_path);
                    }
                 file_source_path=str_contact(file_source_path,filename->d_name);
                 file_destination_path=str_contact(file_destination_path,filename->d_name);
                 if(is_dir(file_source_path))
                 {
                     if(!endwith(file_source_path,'.'))
                     {
                         copy_folder(file_source_path,file_destination_path);
                         }
                     }else
                     {
                         Copy(file_source_path,file_destination_path);
                         }
        }
    }
//遍历所有文件
void traverseAB(char* path,char* path2)
{
    DIR *A =NULL,*B=NULL;//d-A,z-B
    struct dirent *dp=NULL,*dt=NULL;
    struct stat stA,stB;//st-stA,qt-stB
    char lenA[MAX_PATH_LEN]={0};//p-lenA
    char lenB[MAX_PATH_LEN]={0};//t-lenB
    char lenC[MAX_PATH_LEN]={0};//q-lenC
    if(stat(path,&stA)<0||!S_ISDIR(stA.st_mode))
    {
        printf("invaild path:%s\n",path);
        return;
        }
    if(!(A=opendir(path)))
    {
        printf("opendir[%s] error: %m\n",path);
        return;
        }
    if(stat(path2,&stB)<0||!S_ISDIR(stB.st_mode))
    {
        printf("invalid path:%s\n",path2);
        return;
        }
    if(!(B=opendir(path2)))
    {
        printf("opendir[%s] error :%m\n",path2);
        return;
        }
    while((dp=readdir(A))!=NULL)
    {
        if((!strncmp(dp->d_name,".",1))||(!strncmp(dp->d_name,"..",2)))
            continue;
        snprintf(lenA,sizeof(lenA)-1,"%s/%s",path,dp->d_name);
        stat(lenA,&stA);
    while((dt=readdir(B))!=NULL)
    {
        snprintf(lenB,sizeof(lenB)-1,"%s/%s",path2,dt->d_name);
        stat(lenB,&stB);
        snprintf(lenC,sizeof(lenC)-1,"%s/%s",path2,dp->d_name);
        if((S_ISDIR(stA.st_mode)&&S_ISDIR(stB.st_mode))&&strcmp(dp->d_name,dt->d_name)==0)
        {
            traverseAB(lenA,lenB);
            }else if((!S_ISDIR(stA.st_mode)&&!S_ISDIR(stB.st_mode))&&strcmp(dp->d_name,dt->d_name)==0&&difftime(stA.st_mtime,stB.st_mtime)!=0)
            {
                FILE *file;
                file=fopen(lenB,"w");
                fclose(file);
                Copy(lenA,lenB);
                }
            if((access(lenC,F_OK)==-1))
            {
                    if((S_ISDIR(stA.st_mode)))
                    {
                        mkdir(lenC,0777);
                        copy_folder(lenA,lenC);
                        }
                    if(!(S_ISDIR(stA.st_mode)))
                    {
                        FILE *file;
                        if((access(lenC,F_OK))!=-1)
                        {
                            continue;
                            }else
                            {
                                file=fopen(lenC,"w+");
                                }
                                fclose(file);
                                Copy(lenA,lenC);
                        }
                }
        }
        closedir(B);
        B=opendir(path2);
    }
}
//删除已存在文件
void remove_dir(const char *dir)
{
    char cur_dir[]=".";
    char up_dir[]="..";
    char dir_name[128];
    DIR *dirp;
    struct dirent *dp;
    struct stat dir_stat;
    if(access(dir,F_OK)!=0)
    {
        return 0;
        }
    if(stat(dir,&dir_stat)>0)
    {
        perror("get directory stat error\n");
        return -1;
        }
    if(S_ISREG(dir_stat.st_mode))
    {
        remove(dir);
        }else if(S_ISDIR(dir_stat.st_mode))
        {
            dirp=opendir(dir);
            while((dp=readdir(dirp))!=NULL)
            {
                if((strcmp(cur_dir,dp->d_name)==0)||(strcmp(up_dir,dp->d_name)==0))
                {
                    continue;
                    }
                sprintf(dir_name,"%s/%s",dir,dp->d_name);
                remove_dir(dir_name);
                }
                closedir(dirp);
                rmdir(dir);
            }else{
                perror("unknow file type!\n");
                }
    }
//遍历文件
void traverse(char* path,char* path2)
{
    DIR *A=NULL,*B=NULL;//d-A,z-B
    struct dirent *dp=NULL, *dt=NULL;
    struct stat stA,stB;//st-stA,qt-stB
    char lenA[MAX_PATH_LEN]={0};//p-lenA
    char lenB[MAX_PATH_LEN]={0};//t-lenB
    char lenC[MAX_PATH_LEN]={0};//q-lenC
    if(stat(path,&stA)<0||!S_ISDIR(stA.st_mode))
    {
        printf("invalid path:%s\n",path);
        return;
        }
    if(!(A=opendir(path)))
    {
        printf("opendir[%s] error:%m\n",path);
        return;
        }
    if(stat(path2,&stB)<0||!S_ISDIR(stB.st_mode))
    {
        printf("invalid path:%s\n",path2);
        return;
        }
    if(!(B=opendir(path2)))
    {
        printf("opendir[%s] error:%m\n",path2);
        return;
        }
    while((dp=readdir(A))!=NULL)
    {
        if((!strncmp(dp->d_name,".",1))||(!strncmp(dp->d_name,"..",2)))
            continue;
        snprintf(lenA,sizeof(lenA)-1,"%s/%s",path,dp->d_name);
        stat(lenA,&stA);
    while((dt=readdir(B))!=NULL)
    {
        snprintf(lenB,sizeof(lenB)-1,"%s/%s",path2,dt->d_name);
        stat(lenB,&stB);
        snprintf(lenC,sizeof(lenC)-1,"%s/%s",path2,dp->d_name);
        if((S_ISDIR(stA.st_mode)&&S_ISDIR(stB.st_mode))&&strcmp(dp->d_name,dt->d_name)==0)
        {
            traverse(lenA,lenB);
            }else if((!S_ISDIR(stA.st_mode)&&!S_ISDIR(stB.st_mode))&&strcmp(dp->d_name,dt->d_name)==0&&difftime(stA.st_mtime,stB.st_mtime)>0)
            {
                FILE *file;
                file=fopen(lenB,"w");
                fclose(file);
                Copy(lenA,lenB);
                }else if((!S_ISDIR(stA.st_mode)&&!S_ISDIR(stB.st_mode))&&strcmp(dp->d_name,dt->d_name)==0&&difftime(stA.st_mtime,stB.st_mtime)<0)
                {
                    FILE *file;
                    file=fopen(lenA,"w");
                    fclose(file);
                    Copy(lenB,lenA);
                    }
                if((access(lenC,F_OK)==-1))
                {
                    if((S_ISDIR(stA.st_mode)))
                    {
                        mkdir(lenC,0777);
                        copy_folder(lenA,lenC);
                        }
                    if(!(S_ISDIR(stA.st_mode)))
                    {
                        FILE *file;
                        if((access(lenC,F_OK))!=-1)
                        {
                            continue;
                            }else
                            {
                                file=fopen(lenC,"w+");
                                }
                                fclose(file);
                                Copy(lenA,lenC);
                        }
                    }
        }
        closedir(B);
        B=opendir(path2);
        }
    }
//遍历文件删除已有文件
void traverseBA(char* path,char* path2)
{
    DIR *A=NULL,*B=NULL;//d-A,z-B
    struct dirent *dp=NULL,*dt=NULL;
    struct stat stA,stB;//st-stA,qt-stB
    char lenA[MAX_PATH_LEN]={0};//P-lenA
    char lenB[MAX_PATH_LEN]={0};//t-lenB
    char lenC[MAX_PATH_LEN]={0};//q-lenC
    if(stat(path,&stA)<0||!S_ISDIR(stA.st_mode))
    {
        printf("invalid path:%s\n",path);
        return;
        }
    if(!(A=opendir(path)))
    {
        printf("opendir[%s] error:%m\n",path);
        return;
        }
    if(stat(path2,&stB)<0||!S_ISDIR(stB.st_mode))
    {
        printf("invalid path:%s\n",path2);
        return;
        }
    if(!(B=opendir(path2)))
    {
        printf("opendir[%s] error:%m\n",path2);
        return;
        }
    while((dp=readdir(A))!=NULL)
    {
        if((!strncmp(dp->d_name,".",1))||(!strncmp(dp->d_name,"..",2)))
            continue;
        snprintf(lenA,sizeof(lenA)-1,"%s/%s",path,dp->d_name);
        stat(lenA,&stA);
        while((dt=readdir(B))!=NULL)
        {
            snprintf(lenB,sizeof(lenA)-1,"%s/%s",path2,dp->d_name);
            stat(lenB,&stB);
            snprintf(lenC,sizeof(lenC)-1,"%s/%s",path2,dt->d_name);
            if((S_ISDIR(stA.st_mode)&&S_ISDIR(stB.st_mode))&&strcmp(dp->d_name,dt->d_name)==0)
            {
                traverseBA(lenA,lenB);
                }
            if((access(lenC,F_OK)==-1))
            {
                if((S_ISDIR(stA.st_mode)))
                {
                    remove_dir(lenA);
                    }
                if(!(S_ISDIR(stA.st_mode)))
                {
                    remove(lenA);
                    }
                }
            }
            closedir(B);
            B=opendir(path2);
        }

    }
//同步备份进度
void ProgressBar()
{
   int n = 10;
	for(int i=0;i<n;i++)
	{
		if(i==0)	printf("[");

		printf("*");
	}
	printf("] 100%\n");
}
